import { BadRequestException, Inject, Injectable } from '@nestjs/common';
import { CreateBookingDto } from './dto/create-booking.dto';
import { UpdateBookingDto } from './dto/update-booking.dto';

import { InjectEntityManager } from "@nestjs/typeorm";
import { Between, EntityManager, LessThanOrEqual, Like, MoreThan, MoreThanOrEqual } from "typeorm";
import { User } from 'src/user/entities/user.entity';
import { MeetingRoom } from 'src/meeting-room/entities/meeting-room.entity';
import { Booking } from './entities/booking.entity';

import { RedisService } from "../redis/redis.service";
import { EmailService } from "../email/email.service";

@Injectable()
export class BookingService {
  @InjectEntityManager()
  private entityManager: EntityManager;
  @Inject(RedisService)
  private redisService: RedisService;
  @Inject(EmailService)
  private emailService: EmailService;

  /* 初始化一些数据--写在service中，不通过接口调用，通过nestjs的repl模式调用 */
  async initData() {
    const user1 = await this.entityManager.findOneBy(User, {
      id: 1
    });
    const user2 = await this.entityManager.findOneBy(User, {
      id: 2
    });

    const room1 = await this.entityManager.findOneBy(MeetingRoom, {
      id: 3
    });
    const room2 = await this.entityManager.findOneBy(MeetingRoom, {
      id: 6
    });

    const booking1 = new Booking();
    booking1.room = room1;
    booking1.user = user1;
    booking1.startTime = new Date();
    booking1.endTime = new Date(Date.now() + 1000 * 60 * 60);
    await this.entityManager.save(Booking, booking1);

    const booking2 = new Booking();
    booking2.room = room2;
    booking2.user = user2;
    booking2.startTime = new Date();
    booking2.endTime = new Date(Date.now() + 1000 * 60 * 60);
    await this.entityManager.save(Booking, booking2);

    const booking3 = new Booking();
    booking3.room = room1;
    booking3.user = user2;
    booking3.startTime = new Date();
    booking3.endTime = new Date(Date.now() + 1000 * 60 * 60);
    await this.entityManager.save(Booking, booking3);

    const booking4 = new Booking();
    booking4.room = room2;
    booking4.user = user1;
    booking4.startTime = new Date();
    booking4.endTime = new Date(Date.now() + 1000 * 60 * 60);
    await this.entityManager.save(Booking, booking4);
  }

  /* 新增一条预定记录 */
  async add(booking: CreateBookingDto, useId: number) {
    const meetingRoom = await this.entityManager.findOneBy(MeetingRoom, {
      id: booking.meetingRoomId
    });

    if(!meetingRoom) {
      throw new BadRequestException("会议室不存在");
    }
    const user = await this.entityManager.findOneBy(User, {
      id: useId
    });

    const bookingRoom = new Booking();
    bookingRoom.room = meetingRoom;
    bookingRoom.user = user;
    bookingRoom.startTime = new Date(booking.startTime);
    bookingRoom.endTime = new Date(booking.endTime);

    // 需要判断一下，当前会议室是否可以被预定（一般的做法是前端列出没有被预定的时间段，这里我们简化一下，直接查找预定记录里有没有传入时间段的预定记录）
    const res = await this.entityManager.findOneBy(Booking, {
      room: meetingRoom,
      startTime: LessThanOrEqual(booking.startTime) as any,
      endTime: MoreThanOrEqual(booking.endTime) as any
    });
    if(res) {
      throw new BadRequestException("该时间段已被预定");
    }

    await this.entityManager.save(Booking, bookingRoom);
  }
  /* 删除一条预定记录 */
  remove(id: number) {
    return `This action removes a #${id} booking`;
  }
  /* 修改一条预定记录 */
  update(id: number, updateBookingDto: UpdateBookingDto) {
    return `This action updates a #${id} booking`;
  }
  /* 查询所有预定记录 */
  async findAll(pageNo: number, pageSize: number, username: string, meetingRoomName: string, meetingRoomPosition: string, bookingTimeRangeStart: number, bookingTimeRangeEnd: number ) {
    const skipCount = (pageNo-1)*pageSize;

    const condition: Record<string, any> = {};

    if(username) {
      condition.user = {
        username: Like(`%${username}%`)
      }
    }
    if(meetingRoomName) {
      condition.room = {
        name: Like(`%${meetingRoomName}%`)
      }
    }
    if(meetingRoomPosition) {
      if(!condition.room) {
        condition.room ={}
      }
      condition.room.location = Like(`%${meetingRoomPosition}%`);
    }
    if(bookingTimeRangeStart) {
      if(!bookingTimeRangeEnd) {
        bookingTimeRangeEnd = bookingTimeRangeStart + 60*60*1000;
      }
      condition.startTime = Between(new Date(bookingTimeRangeStart), new Date(bookingTimeRangeEnd))
    }

    const [bookings, totalCount] = await this.entityManager.findAndCount(Booking, {
      // 使用select修改返回的信息，把用户密码信息过滤掉，当然如果闲麻烦也可以在返回时手动删除掉密码信息
      /* select: {
        id: true,
        startTime: true,
        user: {
          id: true,
          nickName: true
        }
      }, */
      where: condition,
      relations: {
        user: true,
        room: true
      },
      skip: skipCount,
      take: pageSize
    });

    return {
      // 不想适应select可以在返回时手动删除
      bookings: bookings.map(item => {
        delete item.user.password;
        return item;
      }),
      totalCount
    }
  }
  /* 查询一条预定记录，根据ID */
  findOne(id: number) {
    return `This action returns a #${id} booking`;
  }

  /* 其他操作 */
  // 同意预定申请
  async apply(id: number) {
    await this.entityManager.update(Booking, {id}, {status: "审批通过"});
    return "success";
  }
  // 取消预定申请
  async reject(id: number) {
    await this.entityManager.update(Booking, {id}, {status: "审批驳回"});
    return "success";
  }
  // 解除预定申请
  async unbind(id: number) {
    await this.entityManager.update(Booking, {id}, {status: "已解除"});
    return "success";
  }
  // 催办--一般情况是发邮箱发短信，但是我们没有开通短信服务就只发邮件；正常业务不是每次催办都发邮件，一般半小时发一次邮件，这个可以通过redis实现
  async urge(id: number) {
    const flag = await this.redisService.get(`urge_${id}`);

    if(flag) {
      return "半小时内只能催办一次，请耐心等待";
    }

    let email = await this.redisService.get("admin_email");
    if(!email) {
      const admin = await this.entityManager.findOne(User, {
        select: {
          email: true
        },
        where: {
          isAdmin: true
        }
      });

      email = admin.email;

      this.redisService.set("admin_email", email);
    }

    this.emailService.sendMail({
      to: email,
      subject: "预定申请催办提醒",
      html: `id为${id}的预定申请正在等待审批`
    });
    
    this.redisService.set(`urge_${id}`, 1, 60*30);
  }

}
